home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
public
/
plan
/
src
/
time.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
8KB
|
289 lines
/*
* Convert date and time data formats.
*
* tm_to_time(tm) convert tm struct to seconds since 1/1/70
* time_to_tm(tp) convert seconds since 1/1/70 to tm struct
* get_time() return current time in seconds since 1/1/70
* set_tzone() figure out current timezone (config.tzone)
*/
#include <stdio.h>
#if defined(MIPS) || defined(NEWSOS4)
#include <sys/types.h>
#endif
#include <time.h>
#include <X11/StringDefs.h>
#include "conf.h"
#undef DEBUG /* define this to debug timezone calc */
extern char *getenv();
extern void get_rsrc();
extern struct config config; /* global configuration data */
short monthlen[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
short monthbegin[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
/*
* convert a tm structure (d.m.y h:m:s) to a time in seconds since 1/1/70.
* The difference to mktime() is that the result modulo 86400 is always
* the time, regardless of timezones and daylight saving time. This makes
* it much easier to process days with different DST status.
* This routine only works correctly for the range 1970..2069.
*/
time_t tm_to_time(tm)
struct tm *tm; /* time/date to convert */
{
time_t t; /* return value */
t = monthbegin[tm->tm_mon] /* full months */
+ tm->tm_mday-1 /* full days */
+ (!(tm->tm_year & 3) && tm->tm_mon > 1); /* leap day this year*/
tm->tm_yday = t;
t += 365 * (tm->tm_year - 70) /* full years */
+ (tm->tm_year - 69)/4; /* past leap days */
tm->tm_wday = (t + 4) % 7;
t = t*86400 + tm->tm_hour*3600 + tm->tm_min*60 + tm->tm_sec;
if (tm->tm_mday > monthlen[tm->tm_mon] +
(!(tm->tm_year & 3) && tm->tm_mon == 1))
return((time_t)-1);
return(t);
}
/*
* convert time in seconds since 1/1/70 to a tm structure, and also fill in
* the week number, julian date, and weekday. The difference to localtime()
* is that timezones and daylight saving time are ignored.
* This routine only works correctly for the range 1970..2069.
*/
struct tm *time_to_tm(t)
time_t t; /* time to convert */
{
int n, l; /* temp */
static struct tm tm; /* returned tm */
tm.tm_sec = t % 60; t /= 60;
tm.tm_min = t % 60; t /= 60;
tm.tm_hour = t % 24; t /= 24;
tm.tm_wday = (t + 4) % 7;
n = t / (365+365+366+365);
tm.tm_year = 70 + n*4; t -= n * (365+365+366+365);
if (t > 364) tm.tm_year++, t -= 365;
if (t > 364) tm.tm_year++, t -= 365;
if (t > 365) tm.tm_year++, t -= 366;
tm.tm_yday = t;
for (n=0; n < 11; n++) {
l = monthlen[n] + (n==1 && !(tm.tm_year&3));
if (t < l)
break;
t -= l;
}
tm.tm_mon = n;
tm.tm_mday = t+1;
return(&tm);
}
/*
* return current time in seconds since 1/1/70. The timezone is applied
* such that the return value modulo 86400 is the number of seconds since
* midnight.
*/
time_t get_time()
{
return(time(0) - config.tzone + config.adjust_time);
}
/*
* return the current time zone as the number of seconds as difference
* to GMT (UTC) in seconds. Since all the tricks with tm_isdst, gmtoff,
* _timezone etc turned out to be nonportable, I am now parsing the TZ
* environment variable directly. There is nothing standard about standard
* libraries when it comes to time calculation!
*/
void set_tzone()
{
register struct config *c = &config;
time_t now; /* current local time */
time_t tod; /* time-of-day, 0..86399 */
struct tm *tm; /* julian date of <now> */
now = time(0) - c->raw_tzone;
tod = now % 86400;
tm = time_to_tm(now);
switch(c->dst_flag) {
case 0: /* dst on */
c->tzone = c->raw_tzone - 3600;
break;
case 1: /* dst off */
c->tzone = c->raw_tzone;
break;
case 2: /* auto dst */
if ((tm->tm_yday > c->dst_begin ||
tm->tm_yday == c->dst_begin && tod >= c->dst_begin_time)&&
(tm->tm_yday == c->dst_end && tod < c->dst_end_time ||
tm->tm_yday < c->dst_end))
c->tzone = c->raw_tzone - 3600;
else
c->tzone = c->raw_tzone;
}
}
/*
* Figure out reasonable values for the config fields raw_tzone, dst_flag,
* dst_begin, and dst_end. This is used for defaults if the .dayplan file
* does not specify the adjustment, or when the user presses Guess in the
* Adjust Time popup.
*/
#define DST_BEGIN 64 /* default begin of DST */
#define DST_END 220 /* default end of DST */
#ifdef DEBUG
static char *zone_time_string();
#endif
static get_zone_time();
guess_tzone()
{
char *tz=0; /* timezone string (TZ) */
int zone=0, dst= -3600; /* difference from GMT */
int begin=0, begintime=0; /* dst begin: julian day/time*/
int end=0, endtime=0; /* dst end: julian day/time */
if (((tz = getenv("PLAN_TZ")) && *tz ||
(tz = getenv("TZ")) && *tz) && strrchr("0123456789-",tz[3])){
do {
if (!*tz++ || !*tz++ || !*tz++) /* MET */
break;
zone = get_zone_time(&tz, 0); /* time */
dst = zone - 3600;
if (!*tz++ || !*tz++ || !*tz++) /* MST */
break;
dst = get_zone_time(&tz, dst); /* time */
if (*tz++ != ';') /* ;begin */
break;
while (*tz >= '0' && *tz <= '9')
begin = begin*10 + *tz++ - '0';
if (*tz == '/') { /* /time */
tz++;
begintime = get_zone_time(&tz, 0);
}
if (*tz++ != ',') /* ,end */
break;
while (*tz >= '0' && *tz <= '9')
end = end*10 + *tz++ - '0';
if (*tz++ == '/') /* /time */
endtime = get_zone_time(&tz, 0);
} while (0);
} else {
#if defined(SVR4) || defined(SOLARIS2)
time_t now = get_time();
struct tm *tm = localtime(&now);
time_t h = tm->tm_hour;
struct tm *gmt = gmtime(&now);
zone = (gmt->tm_hour - h) * 3600;
dst = zone - 3600;
#else
#if defined(bsdi) || defined(SUN) || defined(SVR4)
time_t now;
struct tm *tm;
tzset();
now = time(0);
tm = localtime(&now);
zone = -tm->tm_gmtoff;
#endif
#endif
}
#ifdef DEBUG
if (tz = getenv("PLAN_TZ"))
printf("PLAN_TZ env variable: %s\n", tz);
if (tz = getenv("TZ"))
printf("TZ env variable: %s\n", tz);
printf("standard timezone: GMT%s\n", zone_time_string(zone));
printf("DST timezone: GMT%s\n", zone_time_string(dst));
printf("DST start: %s on julian day %d\n",
zone_time_string(begintime)+1, begin);
printf("DST end: %s on julian day %d\n",
zone_time_string(endtime)+1, end);
#endif
if (!begin) { /* defaults */
begin = DST_BEGIN;
begintime = 2*3600;
}
if (!end) {
end = DST_END;
endtime = 2*3600;
}
config.raw_tzone = zone;
config.dst_flag = 2;
config.dst_begin = begin;
config.dst_end = end;
config.dst_begin_time = begintime;
config.dst_end_time = endtime;
#ifdef DEBUG
printf("current timezone: GMT%s\n", zone_time_string(zone));
#endif
}
/*
* parse a time string of the form [hours[:minutes[:seconds]]], return seconds
*/
static get_zone_time(tzp, zdefault)
char **tzp;
int zdefault;
{
char *tz = *tzp;
int i, num, zone = 0;
int sign = 1;
if (*tz == '-') tz++, sign = -1;
if (*tz == '+') tz++;
for (i=0; i < 3; i++) {
zone *= 60;
num = 0;
while (*tz >= '0' && *tz <= '9')
num = num*10 + *tz++ - '0';
zone += num;
tz += *tz == ':';
}
zone *= sign;
if (tz == *tzp)
zone = zdefault;
*tzp = tz;
return(zone);
}
/*
* return a number of seconds as a string "+/-hours:minutes:seconds"
*/
#ifdef DEBUG
static char *zone_time_string(t)
int t;
{
static char buf[12];
t %= 86400;
buf[0] = t < 0 ? '-' : '+';
if (t < 0)
t = -t;
sprintf(buf+1, "%02d:%02d:%02d", t/3600, (t/60)%60, t%60);
return(buf);
}
#endif